﻿Imports Microsoft.DirectX
Imports Microsoft.DirectX.Direct3D
Imports System.Threading
Imports System.Runtime.InteropServices

Namespace Engine

    Module mEngine

        Friend Declare Auto Function PeekMessage Lib "user32.dll" ( _
        ByRef lpMsg As MessageStruct, _
        ByVal hWnd As IntPtr, _
        ByVal wMsgFilterMin As Integer, _
        ByVal wMsgFilterMax As Integer, _
        ByVal wRemoveMsg As Integer _
    ) As Boolean

        <StructLayout(LayoutKind.Sequential)> _
        Public Structure MessageStruct
            Public HWnd As IntPtr
            Public Msg As Integer
            Public WParam As IntPtr
            Public LParam As IntPtr
            Public Time As Integer
            Public P As System.Drawing.Point
        End Structure

        Public threadGame As Thread

        Public bEnding As Boolean

        Public Sub GameLoop()

            Randomize()

            Application.DoEvents()

            DirectX.Init()
            Libs.Init()
            Mouse.Init()
            Editor.Init()

            bEnding = False

            'Test.Init()
            Do Until bEnding

                Mouse.DoInputs()
                Keyboard.DoInputs()
                Timers.DoTimers()

                If DirectX.DeviceLost Then
                    DirectX.DeviceRecover()
                End If

                If Not DirectX.DeviceLost Then

                    DrawGame()

                End If

                'If Not AppIsIdle() Then
                Try
                    Application.DoEvents()
                Catch ex As Exception
                    Debug.Print("Application.DoEvents() failed in Engine.GameLoop()")
                End Try
                'End If

            Loop

            Editor.Shutdown()
            Mouse.Shutdown()
            Libs.Shutdown()
            DirectX.Shutdown()

        End Sub

        Private Sub DrawGame()

            Static Dim iFPS As Integer, iFrames As Integer, iTicks As Long

            Windows.DrawWindows(DirectX.DrawingMode.Overlay)

            DirectX.D3D.SetRenderTarget(0, DirectX.GameSurface)

            DirectX.D3D.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, Color.Black, 1.0, 0)

            DirectX.D3D.BeginScene()

            DirectX.GameSprite.Begin(SpriteFlags.AlphaBlend)
            Engine.SetDrawModeNormal(1.0F, Color.White)
            Windows.DrawWindows(DirectX.DrawingMode.Normal)
            GUI.MouseDragItem.DrawMouseDragItem(DirectX.DrawingMode.Normal)
            DirectX.GameSprite.End()

            DirectX.GameSprite.Begin(SpriteFlags.AlphaBlend)
            Engine.SetDrawModeTinted(1.0F, Color.Red)
            Windows.DrawWindows(DirectX.DrawingMode.Tinted)
            DirectX.GameSprite.End()

            Engine.UseLineShader()

            Engine.SetDrawModeNormal(1.0F, Color.White)
            Windows.DrawWindows(DirectX.DrawingMode.Line)

            Engine.ResetShader()

            Engine.SetDrawModeNormal(1.0, Color.White)
            Windows.DrawWindows(DirectX.DrawingMode.Text)

            'Draw fps count
            DirectX.ProFont9.DrawNormalText("FPS: " & iFPS.ToString, 2, 2, Color.Red, 0.01F)

            DirectX.D3D.EndScene()


            Try
                DirectX.D3D.Present()
            Catch e As DeviceLostException
                DirectX.DeviceLost = True
            End Try

            'Debug.Print("Frame")

            If iTicks = 0 Then iTicks = DateTime.Now.Ticks

            iFrames += 1
            If iTicks + 10000000 <= DateTime.Now.Ticks Then
                iFPS = iFrames
                iTicks += 10000000
                iFrames = 0
            End If

        End Sub

        Public Sub DrawLine(ByRef X1 As Single, ByRef X2 As Single, ByRef Y1 As Single, ByRef Y2 As Single, ByRef z As Single, ByRef Width As Single, ByRef Colour As System.Drawing.Color)

            '    DirectX.GameSprite.End()

            Dim aLineVertex As CustomVertex.TransformedColored() = New CustomVertex.TransformedColored(0 To 1) {}
            'Set the starting point of the line
            aLineVertex(0).Position = New Vector4(X1, Y1, z, 0)
            aLineVertex(0).Color = Colour.ToArgb

            'Set the ending point of the line
            aLineVertex(1).Position = New Vector4(X2, Y2, z, 0)
            aLineVertex(1).Color = Colour.ToArgb

            'Render the line
            'DirectX.D3D.SetTexture(0, Nothing)

            '    UseLineShader()

            DirectX.D3D.DrawUserPrimitives(PrimitiveType.LineList, 1, aLineVertex)

            '    ResetShader()

            '    DirectX.GameSprite.Begin(SpriteFlags.AlphaBlend)

        End Sub

        'Private Sub DrawLine(ByRef X1 As Single, ByRef X2 As Single, ByRef Y1 As Single, ByRef Y2 As Single, ByRef Width As Single, ByRef Colour As System.Drawing.Color)

        'Dim aLineVectors(1) As Microsoft.DirectX.Vector2

        'Set the starting point of the line
        'aLineVectors(0).X = X1 '- 0.5
        'aLineVectors(0).Y = Y1 '- 0.5

        'Set the ending point of the line
        'aLineVectors(1).X = X2 '- 0.5
        'aLineVectors(1).Y = Y2 '- 0.5

        'Give the line it's width (there's that width you were needing....)  
        'DirectX.Line.Width = Width

        'DirectX.GameSprite.End()
        'Render the line
        'DirectX.Line.Begin()
        'DirectX.Line.Draw(aLineVectors, Colour)
        'DirectX.Line.End()
        'DirectX.GameSprite.Begin(SpriteFlags.AlphaBlend)

        'End Sub

        Public Sub DrawBox(ByRef rect As Rectangle, ByRef z As Single, ByRef width As Single, ByRef colour As Color)
            DrawBox(rect.Left, rect.Right, rect.Top, rect.Bottom, z, width, colour)
        End Sub

        Public Sub DrawBox(ByRef X1 As Single, ByRef X2 As Single, ByRef Y1 As Single, ByRef Y2 As Single, ByRef z As Single, ByRef Width As Single, ByRef Colour As System.Drawing.Color)

            DrawLine(X1, X1, Y1, Y2, z, Width, Colour)
            DrawLine(X2, X2, Y1, Y2, z, Width, Colour)
            DrawLine(X1, X2, Y1, Y1, z, Width, Colour)
            DrawLine(X1, X2, Y2, Y2, z, Width, Colour)

        End Sub

        'Public Sub DrawBox(ByRef X1 As Single, ByRef X2 As Single, ByRef Y1 As Single, ByRef Y2 As Single, ByRef Width As Single, ByRef Colour As System.Drawing.Color)

        'Dim aLineVectors(1) As Microsoft.DirectX.Vector2

        'DirectX.Line.Width = Width

        'DirectX.Line.Begin()

        'aLineVectors(0).X = X1 - 0.5
        'aLineVectors(0).Y = Y1 '+ 0.5

        'aLineVectors(1).X = X2 + 0.5
        'aLineVectors(1).Y = Y1 '+ 0.5

        'DirectX.Line.Draw(aLineVectors, Colour)

        'aLineVectors(0).X = X2 '- 0.5
        'aLineVectors(0).Y = Y1 '+ 0.5

        'aLineVectors(1).X = X2 '+ 0.5
        'aLineVectors(1).Y = Y2 '+ 0.5

        'DirectX.Line.Draw(aLineVectors, Colour)

        'aLineVectors(0).X = X1 - 0.5
        'aLineVectors(0).Y = Y2 '+ 0.5

        'aLineVectors(1).X = X2 + 0.5
        'aLineVectors(1).Y = Y2 '+ 0.5

        'DirectX.Line.Draw(aLineVectors, Colour)

        'aLineVectors(0).X = X1 '- 0.5
        'aLineVectors(0).Y = Y1 '+ 0.5

        'aLineVectors(1).X = X1 '+ 0.5
        'aLineVectors(1).Y = Y2 '+ 0.5

        'DirectX.Line.Draw(aLineVectors, Colour)

        'aLineVectors(2).X = X2 '+ 0.5
        'aLineVectors(2).Y = Y2 '+ 0.5

        'aLineVectors(3).X = X1 '+ 0.5
        'aLineVectors(3).Y = Y2 '+ 0.5

        'aLineVectors(4).X = X1 '+ 0.5
        'aLineVectors(4).Y = Y1 '+ 0.5

        'DirectX.Line.Draw(aLineVectors, Colour)

        'DirectX.Line.End()

        'End Sub

        Public Sub DrawSolidBox(ByRef rect As Rectangle, ByRef z As Single, ByRef colour As Color)
            DrawSolidBox(rect.Left, rect.Right, rect.Top, rect.Bottom, z, colour)
        End Sub

        Public Sub DrawSolidBox(ByRef X1 As Single, ByRef X2 As Single, ByRef Y1 As Single, ByRef Y2 As Single, ByRef z As Single, ByRef colour As System.Drawing.Color)

            'Dim y As Single
            'Dim w As Single

            'If Y1 > Y2 Then
            'w = Y1 - Y2
            'Else
            'w = Y2 - Y1
            'End If

            'y = Y1 + (w / 2)

            'DrawLine(X1, X2, y, y, w, colour)

            'DirectX.GameSprite.End()

            Dim aLineVertex As CustomVertex.TransformedColored() = New CustomVertex.TransformedColored(0 To 4) {}

            aLineVertex(0).Position = New Vector4(X1, Y1, z, 0)
            aLineVertex(0).Color = colour.ToArgb

            aLineVertex(1).Position = New Vector4(X2, Y1, z, 0)
            aLineVertex(1).Color = colour.ToArgb

            aLineVertex(2).Position = New Vector4(X1, Y2, z, 0)
            aLineVertex(2).Color = colour.ToArgb

            aLineVertex(3).Position = New Vector4(X2, Y2, z, 0)
            aLineVertex(3).Color = colour.ToArgb

            'Render the line
            'DirectX.D3D.SetTexture(0, Nothing)

            'UseLineShader()

            'DirectX.D3D.RenderState.ColorVertex = True
            'DirectX.D3D.VertexFormat = CustomVertex.TransformedColored.Format
            DirectX.D3D.DrawUserPrimitives(PrimitiveType.TriangleStrip, 2, aLineVertex)

            'ResetShader()

            'DirectX.GameSprite.Begin(SpriteFlags.AlphaBlend)

        End Sub

        'Dim prevmode As Globals.DrawingMode = Globals.DrawingMode.Normal
        'Dim prevblend As Single = 1.0
        'Dim prevtint As Integer = -1

        'Dim restoremode As Globals.DrawingMode = Globals.DrawingMode.Normal
        'Dim restoreblend As Single = 1.0
        'Dim restoretint As Integer = -1

        'Public Sub RestorePrevDrawMode()
        'SetDrawMode(restoremode, restoreblend, restoretint)
        'End Sub

        Public Sub UseLineShader()

            DirectX.D3D.SetTextureStageState(0, TextureStageStates.AlphaOperation, TextureOperation.Disable)
            DirectX.D3D.SetTextureStageState(0, TextureStageStates.ColorOperation, TextureOperation.Disable)
        End Sub

        Public Sub ResetShader()

            DirectX.D3D.SetTextureStageState(0, TextureStageStates.AlphaOperation, TextureOperation.Modulate)
            DirectX.D3D.SetTextureStageState(0, TextureStageStates.ColorOperation, TextureOperation.SelectArg1)

        End Sub

        'Public Sub SetDrawMode(ByRef mode As Globals.DrawingMode, Optional ByRef blendconst As Single = 1.0, Optional ByRef tintcolor As Integer = -1, Optional ByRef reset As Boolean = False)
        'Exit Sub

        'If prevmode = mode And prevblend = blendconst And prevtint = tintcolor And Not reset Then Exit Sub

        'If Not reset Then
        'Debug.Print("Sprite Reset")
        'DirectX.GameSprite.End()
        'DirectX.GameSprite.Begin(SpriteFlags.AlphaBlend)
        'End If

        'restoremode = prevmode
        'restoreblend = prevblend
        'restoretint = prevtint

        'prevmode = mode
        'prevblend = blendconst
        'prevtint = tintcolor

        'Select Case mode

        'Case Globals.DrawingMode.Normal
        'DirectX.sbNormal.Apply()
        'SetDrawModeNormal(blendconst, Color.FromArgb(tintcolor))

        'Case Globals.DrawingMode.Magic
        'DirectX.sbMagic.Apply()
        'SetDrawModeMagic(blendconst, Color.FromArgb(tintcolor))

        'Case Globals.DrawingMode.Grayscale
        'DirectX.sbGray.Apply()
        'SetDrawModeGrayscale(blendconst, Color.FromArgb(tintcolor))

        'Case Globals.DrawingMode.Tinted
        'DirectX.sbGray.Apply()
        'SetDrawModeTinted(blendconst, Color.FromArgb(tintcolor))

        'End Select

        'End Sub

        Public Sub SetDrawModeNormal(ByRef blendconst As Single, ByRef tintcolor As Color)

            'If blendconst = 1 Then
            'DirectX.D3D.PixelShader = Nothing
            'Else
            'DirectX.D3D.PixelShader = DirectX.AlphaPixelShader
            'DirectX.D3D.SetPixelShaderConstant(0, New Vector4(1.0, 1.0, 1.0, blendconst))
            'End If


            If blendconst = 1.0 Then

                DirectX.D3D.TextureState(1).ColorOperation = TextureOperation.Disable

            Else

                DirectX.D3D.RenderState.TextureFactor = Color.FromArgb(blendconst * 255, 0, 0, 0).ToArgb
                DirectX.D3D.TextureState(1).ColorOperation = TextureOperation.SelectArg1
                DirectX.D3D.TextureState(1).ColorArgument1 = TextureArgument.Current
                DirectX.D3D.TextureState(1).AlphaOperation = TextureOperation.Modulate
                DirectX.D3D.TextureState(1).AlphaArgument1 = TextureArgument.Current
                DirectX.D3D.TextureState(1).AlphaArgument2 = TextureArgument.TFactor
                DirectX.D3D.TextureState(1).ConstantColor = Color.FromArgb(blendconst * 255, 0, 0, 0)
                DirectX.D3D.TextureState(1).ResultArgument = TextureArgument.Current

                DirectX.D3D.TextureState(2).ColorOperation = TextureOperation.Disable
                DirectX.D3D.TextureState(2).AlphaOperation = TextureOperation.Disable

            End If

        End Sub

        Public Sub SetDrawModeShadow(ByRef blendconst As Single)


            'texture factor for luminance

            DirectX.D3D.TextureState(1).ColorOperation = TextureOperation.SelectArg1
            DirectX.D3D.TextureState(1).ColorArgument1 = TextureArgument.Constant
            DirectX.D3D.TextureState(1).AlphaOperation = TextureOperation.Modulate
            DirectX.D3D.TextureState(1).AlphaArgument1 = TextureArgument.Current
            DirectX.D3D.TextureState(1).AlphaArgument2 = TextureArgument.Constant
            DirectX.D3D.TextureState(1).ResultArgument = TextureArgument.Current
            DirectX.D3D.TextureState(1).ConstantColor = Color.FromArgb(255 * blendconst, 0, 0, 0)

            DirectX.D3D.TextureState(2).ColorOperation = TextureOperation.Disable
            DirectX.D3D.TextureState(2).AlphaOperation = TextureOperation.Disable

        End Sub

        Public Sub SetDrawModeTinted(ByRef blendconst As Single, ByRef tintcolor As Color)

            'texture factor for luminance
            DirectX.D3D.RenderState.TextureFactor = (255 << 24) Or ((255 - 29) << 16) Or ((255 - 150) << 8) Or (255 - 76)

            DirectX.D3D.TextureState(1).ColorOperation = TextureOperation.AddSmooth
            DirectX.D3D.TextureState(1).ColorArgument1 = TextureArgument.Current
            DirectX.D3D.TextureState(1).ColorArgument2 = TextureArgument.Constant
            DirectX.D3D.TextureState(1).AlphaOperation = TextureOperation.SelectArg1
            DirectX.D3D.TextureState(1).AlphaArgument1 = TextureArgument.Current
            DirectX.D3D.TextureState(1).ResultArgument = TextureArgument.Temp
            DirectX.D3D.TextureState(1).ConstantColor = Color.Gray

            DirectX.D3D.TextureState(2).ColorOperation = TextureOperation.DotProduct3
            DirectX.D3D.TextureState(2).ColorArgument1 = TextureArgument.Temp
            DirectX.D3D.TextureState(2).ColorArgument2 = TextureArgument.TFactor
            DirectX.D3D.TextureState(2).AlphaOperation = TextureOperation.SelectArg1
            DirectX.D3D.TextureState(2).AlphaArgument1 = TextureArgument.Current
            DirectX.D3D.TextureState(2).ResultArgument = TextureArgument.Temp

            DirectX.D3D.TextureState(3).ColorOperation = TextureOperation.Modulate
            DirectX.D3D.TextureState(3).ColorArgument1 = TextureArgument.Constant
            DirectX.D3D.TextureState(3).ColorArgument2 = TextureArgument.Temp
            DirectX.D3D.TextureState(3).ConstantColor = tintcolor
            DirectX.D3D.TextureState(3).AlphaOperation = TextureOperation.SelectArg1
            DirectX.D3D.TextureState(3).AlphaArgument1 = TextureArgument.Current
            DirectX.D3D.TextureState(3).ResultArgument = TextureArgument.Temp

            DirectX.D3D.TextureState(4).ColorOperation = TextureOperation.SelectArg1
            DirectX.D3D.TextureState(4).ColorArgument1 = TextureArgument.Temp
            DirectX.D3D.TextureState(4).AlphaOperation = TextureOperation.Modulate
            DirectX.D3D.TextureState(4).AlphaArgument1 = TextureArgument.Current
            DirectX.D3D.TextureState(4).AlphaArgument2 = TextureArgument.Constant
            DirectX.D3D.TextureState(4).ConstantColor = Color.FromArgb(blendconst * 255, 0, 0, 0)
            DirectX.D3D.TextureState(4).ResultArgument = TextureArgument.Current

            DirectX.D3D.TextureState(5).ColorOperation = TextureOperation.Disable
            DirectX.D3D.TextureState(5).AlphaOperation = TextureOperation.Disable

        End Sub

        Private Function AppIsIdle() As Boolean
            Static msg As MessageStruct
            Return (PeekMessage(msg, IntPtr.Zero, 0, 0, 0) = 0)
        End Function

    End Module

End Namespace